/*!
 * \file ems_ystream.c
 *
 * \brief 相对于ems_xstream，本页函数直接操作char*，可以在后期将这两个方法融合
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.
 *
 * \version 1.0
 * \author songbb
 * \date 2016/10/24
 *
 */

#include <iconv2utf8.h>
#include "conntrack.h"
#include "frct_comm.h"
#include "frzlib.h"

#include "ems_core.h"
#include "ems_comm.h"
#include "ems_xstream.h"
#include "ems_ystream.h"

int ems_y_readUnsignedByte(char *p_buff
                        , int i_buff_len
                        , int *p_i_buff_offset
                        , unsigned char *p_uc_out)
{
    if (*p_i_buff_offset >= i_buff_len)
        goto error;

    *p_uc_out = (unsigned char) *(p_buff + (*p_i_buff_offset)++);

    return FR_SUCC;
error:
    return FR_FAIL;
}

int ems_y_readByte(char *p_buff
                , int i_buff_len
                , int *p_i_buff_offset
                , char *p_c_out)
{
    if (*p_i_buff_offset >= i_buff_len)
        goto error;

    *p_c_out = *(p_buff + (*p_i_buff_offset)++);

    return FR_SUCC;
error:
    return FR_FAIL;
}

int ems_y_readVarLong(char *p_buff
                    , int i_buff_len
                    , int *p_i_buff_offset
                    , long long *p_ll_out)
{
    char i;
    int k;
    int j;
    *p_ll_out = 0LL;

    if (*p_i_buff_offset >= i_buff_len)
        goto error;

    i = *(p_buff + *p_i_buff_offset);

    if (i == 0xF0)
    {
        *p_ll_out = -1LL;
        (*p_i_buff_offset)++;
        return FR_SUCC;
    }

    if ((i & 0x80) == 0)
    {
        *p_ll_out = i;
        (*p_i_buff_offset)++;
        return FR_SUCC;
    }

    if ((i & 0x40) == 0)
    {
        if (*p_i_buff_offset + 2 > i_buff_len)
            goto error;
        j = (short) (*(p_buff + (*p_i_buff_offset)++) << 8);
        j += (short) (*(p_buff + (*p_i_buff_offset)++) & 0xFF);
        *p_ll_out = j & 0x3FFF;
        return FR_SUCC;
    }

    if ((i & 0x20) == 0)
    {
        if (*p_i_buff_offset + 4 > i_buff_len)
            goto error;
        j = (short) (*(p_buff + (*p_i_buff_offset)++) << 24);
        j += (short) (*(p_buff + (*p_i_buff_offset)++) << 16 & 0xFF0000);
        j += (short) (*(p_buff + (*p_i_buff_offset)++) << 8 & 0xFF00);
        j += (short) (*(p_buff + (*p_i_buff_offset)++) & 0xFF);
        *p_ll_out = j & 0x1FFFFFFF;
        return FR_SUCC;
    }

    j = i & 0xF;
    (*p_i_buff_offset)++;

    if (*p_i_buff_offset + j > i_buff_len)
        goto error;

    *p_ll_out = 0LL;
    for (k = 0; k < j; k++)
    {
        *p_ll_out <<= 8;
        *p_ll_out |= *(p_buff + (*p_i_buff_offset)++) & 0xFF;
    }

    return FR_SUCC;
error:
    return FR_FAIL;
}

int ems_y_readString(L7session_ems *p_st_sess
                    , char *p_buff
                    , int i_buff_len
                    , int *p_i_buff_offset
                    , int i_boolean
                    , char **pp_out
                    , int *p_i_out_len)
{
    int i = ems_getTibjmsEncoding(p_st_sess);
    int n;
    char *p_out = NULL;
    unsigned int ui_out_len = 0;

    if (i_boolean == FR_YES)
    {
        if (ems_y_readUnsignedByte(p_buff, i_buff_len, p_i_buff_offset, (unsigned char *) &n) != FR_SUCC)
            goto error;
        n--;
    }
    else
    {
        long long ll_tmp = 0;
        if (ems_y_readVarLong(p_buff, i_buff_len, p_i_buff_offset, &ll_tmp) != FR_SUCC)
            goto error;
        if (ll_tmp == -1LL)
        {
            *pp_out = NULL;
            *p_i_out_len = 0;
            return FR_SUCC;
        }

        n = (int) ll_tmp;
        if (n <= 0)
            goto error;
    }

    if (n == 1)
    {
        char tmp;
        if (ems_y_readByte(p_buff, i_buff_len, p_i_buff_offset, &tmp) != FR_SUCC)
            goto error;
        *pp_out = frstrdup("");
        *p_i_out_len = 1;
        return FR_SUCC;
    }

    if (*p_i_buff_offset + n > i_buff_len)
        goto error;

    // XXX: 以下部分未按源码实现，如有问题请重新编码
    if (i == 8)
    {
        *pp_out = (char *) frmemdup(p_buff + *p_i_buff_offset, (size_t) n);
        *p_i_out_len = n;
    }
    else
    {
        if (iconv_to_utf8(p_buff + *p_i_buff_offset, (unsigned int) n, p_st_sess->p_encoding, &p_out, &ui_out_len) != FR_SUCC)
            goto error;
        *pp_out = p_out;
        *p_i_out_len = ui_out_len;
    }

    return FR_SUCC;
error:
    return FR_FAIL;
}
